package com.fzy.springsecurity2.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fzy.springsecurity2.bean.TUser;
import com.fzy.springsecurity2.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * @author fzy
 * @version 1.0
 * 创建时间：2024-10-12 18:12
 */

@Slf4j
@Component
// OncePerRequestFilter 能够保证在一次请求只通过一次该过滤器
public class JwtAuthenticationFilter extends OncePerRequestFilter implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 从请求头中获取 token
        String token = request.getHeader("Authorization");
        // 空判断
        if (!StringUtils.hasText(token)) {
            chain.doFilter(request, response);
            return;
        }
        try {
            // 解析token
            Claims claims = JwtUtil.parseJWT(token);
            // 获取 uid
            String uid = claims.getSubject();
            // 从 redis 中获取用户信息
            RedisTemplate<String, String> redisTemplate = context.getBean("redisTemplate", RedisTemplate.class);
            ObjectMapper objectMapper = context.getBean("objectMapper", ObjectMapper.class);
            String json = redisTemplate.opsForValue().get(uid);
            TUser tUser = objectMapper.readValue(json, TUser.class);

            if (tUser == null) {
                chain.doFilter(request, response);
                return;
            }
            // 封装成 Authentication，存入 SecurityContextHolder
            SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
            emptyContext.setAuthentication(UsernamePasswordAuthenticationToken.authenticated(tUser, null, tUser.getAuthorities()));
            SecurityContextHolder.setContext(emptyContext);
        } catch (Exception e) {
            if (this.logger.isDebugEnabled()){
                this.logger.debug("Failed to process authentication request", e);
            }
        }
        chain.doFilter(request, response);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}
